package com.example.langchain4j.service;

import cn.hutool.json.JSONUtil;
import com.deepoove.poi.XWPFTemplate;
import com.example.langchain4j.common.constant.PromptConstant;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.input.PromptTemplate;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class AdminPunishmentNoticeService {

    @Autowired
    @Qualifier("chatLanguageModel")
    private ChatLanguageModel chatLanguageModel;

    @Resource
    private ChaiLiangProcessService chaiLiangProcessService;

    @Resource
    private InterrogationGenerationService interrogationGenerationService;

    private static final String GENERATED_DIR = "src/main/resources/generated";

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 生成行政处罚告知笔录
     * @deprecated 请使用 {@link #generateAdminPunishmentNoticeFromFile} 方法，该方法支持用户上传文件
     * @param caseApprovalContent 立案审批表的JSON内容
     * @param gaozhiType 告知类型："处罚前告知" 或 "听证告知"
     * @param sessionId 会话ID
     * @return 包含filePath, htmlPath, jsonData的结果
     */
    @Deprecated
    public Map<String, Object> generateAdminPunishmentNotice(
            String caseApprovalContent, String gaozhiType, String sessionId) {

        log.info("开始生成行政处罚告知笔录, sessionId: {}, 告知类型: {}", sessionId, gaozhiType);
        log.warn("此方法已废弃，建议使用 generateAdminPunishmentNoticeFromFile 方法");

        try {
            // 解析立案审批表JSON数据
            JsonNode caseData = objectMapper.readTree(caseApprovalContent);

            // 注意：此方法不调用裁量模型，使用空的裁量建议
            String chaiLiangAdvice = "";
            String lawBasis = "";
            String punishmentAmount = "";

            // 构建提示词
            String prompt = buildNoticePrompt(caseData, gaozhiType, chaiLiangAdvice, lawBasis, punishmentAmount);

            // 调用ChatLanguageModel生成告知笔录JSON内容
            log.info("调用ChatLanguageModel生成告知笔录JSON...");
            ChatResponse chatResponse = chatLanguageModel.chat(
                dev.langchain4j.data.message.UserMessage.from(prompt));
            String gaozhiJsonRes = chatResponse.aiMessage().text();
            log.info("原始响应长度: {}", gaozhiJsonRes.length());

            // 清理JSON字符串（移除可能的markdown标记）
            gaozhiJsonRes = cleanJsonString(gaozhiJsonRes);
            log.info("生成的告知笔录JSON: {}", gaozhiJsonRes);

            // 确保generated目录存在
            Path generatedPath = Paths.get(GENERATED_DIR);
            if (!Files.exists(generatedPath)) {
                Files.createDirectories(generatedPath);
            }

            // 生成文件名
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
            String fileName = "行政处罚告知笔录_" + timestamp + ".docx";
            String filePath = GENERATED_DIR + "/" + fileName;

            // 填充word模板并保存到文件
            Map<String, Object> resultMap = JSONUtil.toBean(gaozhiJsonRes, Map.class);
            ClassPathResource resource = new ClassPathResource("行政处罚告知笔录template.docx");
            InputStream templateInputStream = resource.getInputStream();
            XWPFTemplate template = XWPFTemplate.compile(templateInputStream).render(resultMap);

            // 保存到本地文件
            FileOutputStream fileOut = new FileOutputStream(filePath);
            template.write(fileOut);
            fileOut.close();
            template.close();

            log.info("告知笔录文件已保存: {}", filePath);

            // 构建返回结果（字段名与前端保持一致）
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("fileName", fileName);
            result.put("filePath", "http://localhost:8018/api/dify/generated/" + fileName);
            result.put("jsonData", gaozhiJsonRes);
            result.put("chaiLiangAdvice", chaiLiangAdvice);  // 返回裁量建议供参考
            result.put("lawBasis", lawBasis);  // 返回提取的法律依据
            result.put("punishmentAmount", punishmentAmount);  // 返回提取的罚款金额
            result.put("message", "行政处罚告知笔录生成成功");

            log.info("告知笔录生成完成，返回结果: {}", result);
            return result;

        } catch (Exception e) {
            log.error("生成告知笔录失败", e);
            throw new RuntimeException("生成告知笔录失败: " + e.getMessage(), e);
        }
    }

    /**
     * 生成行政处罚告知笔录 - 从文件（用户上传文件方式）
     * @param caseApprovalFile 立案审批表文件（用户上传）
     * @param interrogationFile 询问笔录文件（用户上传）
     * @param gaozhiType 告知类型："处罚前告知" 或 "听证告知"
     * @param sessionId 会话ID
     * @return 包含filePath, htmlPath, jsonData的结果
     */
    public Map<String, Object> generateAdminPunishmentNoticeFromFile(
            MultipartFile caseApprovalFile,
            MultipartFile interrogationFile,
            String gaozhiType,
            String sessionId) {

        log.info("开始生成行政处罚告知笔录（从文件）, sessionId: {}, 告知类型: {}", sessionId, gaozhiType);

        try {
            // 验证文件
            if (caseApprovalFile == null || caseApprovalFile.isEmpty()) {
                throw new RuntimeException("立案审批表文件不能为空");
            }
            if (interrogationFile == null || interrogationFile.isEmpty()) {
                throw new RuntimeException("询问笔录文件不能为空");
            }

            // 1. 首先调用裁量大模型获取真实的法律依据和罚款金额
            log.info("调用裁量大模型获取罚款建议...");
            Map<String, Object> chaiLiangResult = callChaiLiangModel(caseApprovalFile, interrogationFile);
            String chaiLiangAdvice = (String) chaiLiangResult.get("chaiLiangAdvice");
            log.info("裁量大模型建议: {}", chaiLiangAdvice);

            // 2. 从裁量建议中提取法律依据和罚款金额
            String lawBasis = extractLawBasis(chaiLiangAdvice);
            String punishmentAmount = extractPunishmentAmount(chaiLiangAdvice);
            log.info("提取的法律依据: {}, 罚款金额: {}", lawBasis, punishmentAmount);

            // 3. 提取立案审批表和询问笔录的文本内容用于生成告知笔录
            String caseApprovalContent = extractTextFromFile(caseApprovalFile);
            String interrogationContent = extractTextFromFile(interrogationFile);

            // 4. 构建提示词，传入裁量建议、法律依据和罚款金额
            String prompt = buildNoticePromptFromText(caseApprovalContent, interrogationContent,
                    gaozhiType, chaiLiangAdvice, lawBasis, punishmentAmount);

            // 5. 调用ChatLanguageModel生成告知笔录JSON内容
            log.info("调用ChatLanguageModel生成告知笔录JSON...");
            ChatResponse chatResponse = chatLanguageModel.chat(
                dev.langchain4j.data.message.UserMessage.from(prompt));
            String gaozhiJsonRes = chatResponse.aiMessage().text();
            log.info("原始响应长度: {}", gaozhiJsonRes.length());

            // 6. 清理JSON字符串（移除可能的markdown标记）
            gaozhiJsonRes = cleanJsonString(gaozhiJsonRes);
            log.info("生成的告知笔录JSON: {}", gaozhiJsonRes);

            // 确保generated目录存在
            Path generatedPath = Paths.get(GENERATED_DIR);
            if (!Files.exists(generatedPath)) {
                Files.createDirectories(generatedPath);
            }

            // 生成文件名
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
            String fileName = "行政处罚告知笔录_" + timestamp + ".docx";
            String filePath = GENERATED_DIR + "/" + fileName;

            // 填充word模板并保存到文件
            Map<String, Object> resultMap = JSONUtil.toBean(gaozhiJsonRes, Map.class);
            ClassPathResource resource = new ClassPathResource("行政处罚告知笔录template.docx");
            InputStream templateInputStream = resource.getInputStream();
            XWPFTemplate template = XWPFTemplate.compile(templateInputStream).render(resultMap);

            // 保存到本地文件
            FileOutputStream fileOut = new FileOutputStream(filePath);
            template.write(fileOut);
            fileOut.close();
            template.close();

            log.info("告知笔录文件已保存: {}", filePath);

            // 构建返回结果（字段名与前端保持一致）
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("fileName", fileName);
            result.put("filePath", "http://localhost:8018/api/dify/generated/" + fileName);
            result.put("jsonData", gaozhiJsonRes);
            result.put("chaiLiangAdvice", chaiLiangAdvice);  // 返回裁量建议供参考
            result.put("lawBasis", lawBasis);  // 返回提取的法律依据
            result.put("punishmentAmount", punishmentAmount);  // 返回提取的罚款金额
            result.put("message", "行政处罚告知笔录生成成功");

            log.info("告知笔录生成完成，返回结果: {}", result);
            return result;

        } catch (Exception e) {
            log.error("生成告知笔录失败", e);
            throw new RuntimeException("生成告知笔录失败: " + e.getMessage(), e);
        }
    }

    /**
     * 从上传的文件中提取文本内容
     * 使用 Apache POI 从 Word 文档中正确提取文本
     */
    private String extractTextFromFile(MultipartFile file) throws IOException {
        String originalFilename = file.getOriginalFilename();
        log.info("开始提取文件文本: {}", originalFilename);

        if (originalFilename != null && originalFilename.toLowerCase().endsWith(".docx")) {
            try (InputStream is = file.getInputStream();
                 XWPFDocument document = new XWPFDocument(is)) {

                StringBuilder text = new StringBuilder();
                List<XWPFParagraph> paragraphs = document.getParagraphs();

                for (XWPFParagraph paragraph : paragraphs) {
                    String paraText = paragraph.getText();
                    if (paraText != null && !paraText.trim().isEmpty()) {
                        text.append(paraText).append("\n");
                    }
                }

                // 提取表格内容
                document.getTables().forEach(table -> {
                    table.getRows().forEach(row -> {
                        row.getTableCells().forEach(cell -> {
                            String cellText = cell.getText();
                            if (cellText != null && !cellText.trim().isEmpty()) {
                                text.append(cellText).append("\t");
                            }
                        });
                        text.append("\n");
                    });
                });

                String extractedText = text.toString();
                log.info("成功提取文本，长度: {} 字符", extractedText.length());
                return extractedText;

            } catch (Exception e) {
                log.error("从Word文档提取文本失败", e);
                throw new IOException("无法从Word文档提取文本: " + e.getMessage(), e);
            }
        } else {
            // 纯文本文件或其他格式
            String textContent = new String(file.getBytes(), "UTF-8");
            log.info("读取文本文件，长度: {} 字符", textContent.length());
            return textContent;
        }
    }

    /**
     * 调用裁量大模型获取罚款建议（接受用户上传的文件）
     * @param caseApprovalFile 用户上传的立案审批表文件
     * @param interrogationFile 用户上传的询问笔录文件
     */
    private Map<String, Object> callChaiLiangModel(MultipartFile caseApprovalFile, MultipartFile interrogationFile) {
        try {
            log.info("准备调用裁量大模型...");

            if (caseApprovalFile == null || caseApprovalFile.isEmpty()) {
                throw new RuntimeException("立案审批表文件不能为空");
            }

            if (interrogationFile == null || interrogationFile.isEmpty()) {
                throw new RuntimeException("询问笔录文件不能为空");
            }

            log.info("立案审批表文件: {}, 询问笔录文件: {}",
                    caseApprovalFile.getOriginalFilename(),
                    interrogationFile.getOriginalFilename());

            // 调用裁量服务
            log.info("调用ChaiLiangProcessService...");
            Map<String, Object> result = chaiLiangProcessService.processChaiLiangQuery(
                caseApprovalFile,
                interrogationFile
            );

            log.info("裁量大模型调用成功");
            return result;

        } catch (Exception e) {
            log.error("调用裁量大模型失败", e);
            // 如果裁量模型调用失败，返回空建议，让AI自行推断
            Map<String, Object> fallbackResult = new HashMap<>();
            fallbackResult.put("chaiLiangAdvice", "");
            fallbackResult.put("success", false);
            fallbackResult.put("message", "裁量模型调用失败，将使用默认建议");
            return fallbackResult;
        }
    }

    /**
     * 查找最新的立案审批表文件
     */
    private String findLatestCaseApprovalFile() {
        try {
            Path dir = Paths.get(GENERATED_DIR);
            if (!Files.exists(dir)) {
                return null;
            }

            // 查找所有立案审批表文件
            return Files.list(dir)
                .filter(path -> path.getFileName().toString().startsWith("行政处罚立案审批表_"))
                .filter(path -> path.getFileName().toString().endsWith(".docx"))
                .sorted((p1, p2) -> {
                    try {
                        return Files.getLastModifiedTime(p2).compareTo(Files.getLastModifiedTime(p1));
                    } catch (IOException e) {
                        return 0;
                    }
                })
                .findFirst()
                .map(path -> path.getFileName().toString())
                .orElse(null);
        } catch (IOException e) {
            log.error("查找立案审批表文件失败", e);
            return null;
        }
    }

    /**
     * 从裁量建议中提取法律依据
     */
    private String extractLawBasis(String chaiLiangAdvice) {
        if (chaiLiangAdvice == null || chaiLiangAdvice.isEmpty()) {
            return "";
        }

        // 简单的提取逻辑：查找《中华人民共和国消防法》相关条款
        // 实际可以使用更复杂的正则或AI提取
        if (chaiLiangAdvice.contains("《中华人民共和国消防法》")) {
            int start = chaiLiangAdvice.indexOf("《中华人民共和国消防法》");
            int end = chaiLiangAdvice.indexOf("。", start);
            if (end != -1) {
                return chaiLiangAdvice.substring(start, end);
            }
        }

        return "";
    }

    /**
     * 从裁量建议中提取罚款金额
     */
    private String extractPunishmentAmount(String chaiLiangAdvice) {
        if (chaiLiangAdvice == null || chaiLiangAdvice.isEmpty()) {
            return "";
        }

        // 使用正则提取金额，例如：5000元、10000元等
        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("(\\d+)元");
        java.util.regex.Matcher matcher = pattern.matcher(chaiLiangAdvice);
        if (matcher.find()) {
            return matcher.group(0);  // 返回"5000元"这样的格式
        }

        return "";
    }

    /**
     * 构建告知笔录生成提示词
     */
    private String buildNoticePrompt(JsonNode caseData, String gaozhiType,
                                     String chaiLiangAdvice, String lawBasis, String punishmentAmount) {
        PromptTemplate promptTemplate = PromptTemplate.from(PromptConstant.generalGaozhiJson);

        HashMap<String, Object> variables = new HashMap<>();
        variables.put("caseApprovalJson", caseData.toPrettyString());
        variables.put("gaozhi_type", gaozhiType);
        variables.put("chaiLiangAdvice", chaiLiangAdvice != null ? chaiLiangAdvice : "");
        variables.put("lawBasis", lawBasis != null ? lawBasis : "");
        variables.put("punishmentAmount", punishmentAmount != null ? punishmentAmount : "");

        Prompt prompt = promptTemplate.apply(variables);
        return prompt.text();
    }

    /**
     * 从文本内容构建告知笔录生成提示词（用于文件上传方式）
     */
    private String buildNoticePromptFromText(String caseApprovalText, String interrogationText,
                                             String gaozhiType, String chaiLiangAdvice,
                                             String lawBasis, String punishmentAmount) {
        PromptTemplate promptTemplate = PromptTemplate.from(PromptConstant.generalGaozhiJson);

        HashMap<String, Object> variables = new HashMap<>();
        // 将文本内容组合成类似JSON格式的结构供模板使用
        String combinedText = String.format(
            "立案审批表内容:\n%s\n\n询问笔录内容:\n%s",
            caseApprovalText != null ? caseApprovalText : "",
            interrogationText != null ? interrogationText : ""
        );
        variables.put("caseApprovalJson", combinedText);
        variables.put("gaozhi_type", gaozhiType);
        variables.put("chaiLiangAdvice", chaiLiangAdvice != null ? chaiLiangAdvice : "");
        variables.put("lawBasis", lawBasis != null ? lawBasis : "");
        variables.put("punishmentAmount", punishmentAmount != null ? punishmentAmount : "");

        Prompt prompt = promptTemplate.apply(variables);
        return prompt.text();
    }

    /**
     * 清理JSON字符串，移除markdown代码块标记和额外说明
     */
    private String cleanJsonString(String jsonString) {
        if (jsonString == null || jsonString.trim().isEmpty()) {
            return jsonString;
        }

        String cleaned = jsonString.trim();

        // 移除开头的markdown标记
        if (cleaned.startsWith("```json")) {
            cleaned = cleaned.substring(7);
        } else if (cleaned.startsWith("```")) {
            cleaned = cleaned.substring(3);
        }

        // 移除结尾的markdown标记
        if (cleaned.endsWith("```")) {
            cleaned = cleaned.substring(0, cleaned.length() - 3);
        }

        cleaned = cleaned.trim();

        // 特殊处理：提取JSON对象
        int lastBrace = cleaned.lastIndexOf('}');
        if (lastBrace != -1) {
            int braceCount = 1;
            int firstBrace = lastBrace - 1;
            while (firstBrace >= 0 && braceCount > 0) {
                if (cleaned.charAt(firstBrace) == '}') {
                    braceCount++;
                } else if (cleaned.charAt(firstBrace) == '{') {
                    braceCount--;
                }
                firstBrace--;
            }
            firstBrace++;

            if (firstBrace >= 0 && braceCount == 0) {
                String potentialJson = cleaned.substring(firstBrace, lastBrace + 1);
                if (potentialJson.contains("\"") && potentialJson.contains(":")) {
                    cleaned = potentialJson;
                    log.info("从响应中提取到JSON，长度: {}", cleaned.length());
                }
            }
        }

        if (!cleaned.startsWith("{")) {
            int firstBrace = cleaned.indexOf('{');
            int lastBraceSimple = cleaned.lastIndexOf('}');

            if (firstBrace != -1 && lastBraceSimple != -1 && firstBrace < lastBraceSimple) {
                cleaned = cleaned.substring(firstBrace, lastBraceSimple + 1);
            }
        }

        return cleaned.trim();
    }

    /**
     * 自定义的 MultipartFile 实现类，用于从文件创建 MultipartFile 对象
     */
    private static class FileMultipartFile implements MultipartFile {
        private final File file;
        private final String name;
        private final String contentType;

        public FileMultipartFile(File file, String name, String contentType) {
            this.file = file;
            this.name = name;
            this.contentType = contentType;
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public String getOriginalFilename() {
            return file.getName();
        }

        @Override
        public String getContentType() {
            return contentType;
        }

        @Override
        public boolean isEmpty() {
            return file.length() == 0;
        }

        @Override
        public long getSize() {
            return file.length();
        }

        @Override
        public byte[] getBytes() throws IOException {
            return Files.readAllBytes(file.toPath());
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return new FileInputStream(file);
        }

        @Override
        public void transferTo(File dest) throws IOException {
            Files.copy(file.toPath(), dest.toPath());
        }
    }
}
